#include "gpio-spi.h"

/**************************SPI模式配置*********************************
  Mode1：CPOL=0，CPHA=0
  Mode2：CPOL=0，CPHA=1
  Mode3：CPOL=1，CPHA=0
  Mode4：CPOL=1，CPHA=1

  时钟极性CPOL是用来配置SCLK的电平出于哪种状态时是空闲态或者有效态，时钟相位CPHA
  是用来配置数据采样是在第几个边沿：
  CPOL=0，表示当SCLK=0时处于空闲态，所以有效状态就是SCLK处于高电平时
  CPOL=1，表示当SCLK=1时处于空闲态，所以有效状态就是SCLK处于低电平时
  CPHA=0，表示数据采样是在第1个边沿，数据发送在第2个边沿
  CPHA=1，表示数据采样是在第2个边沿，数据发送在第1个边沿

 ********************************************************************/


#define SPI_DELAY_RW 20
#define spi_debug(format,...)
//#define spi_debug printf

#define CHECK_PORTING

/*********************************************************************
 * @fn      SPISimulateInit
 *
 * @brief   模拟SPI初始化
 *
 *
 * @param   none
 *
 * @return  none
 */
void SPISimulateInit(struct spi_device_info *pSPIdev)
{
    if(!pSPIdev)
    {
        while(1);
    }

    // SPI communication mode
    if( (pSPIdev->cmm_mode != Mode_1) &&
        (pSPIdev->cmm_mode != Mode_2) &&
        (pSPIdev->cmm_mode != Mode_3) &&
        (pSPIdev->cmm_mode != Mode_4))
    {
        while(1);
    }

    // Delay
    if(!pSPIdev->do_delay_us)
    {
        while(1);
    }

    // CS
    if(!pSPIdev->cfg_nss_dir)
    {
        spi_debug("Warning ! fun not set for CS\n");
    }

    // CS
    if(!pSPIdev->cfg_nss_dir)
    {
        spi_debug("Warning ! fun not set for CS\n");
    }
    if(!pSPIdev->set_nss_pin)
    {
        spi_debug("Warning ! fun not set for CS\n");
    }
    if(!pSPIdev->clr_nss_pin)
    {
        while(1);
        spi_debug("Warning ! fun not set for CS\n");
    }

    // CLK
    if(!pSPIdev->cfg_clk_dir)
    {
        while(1);
    }
    if(!pSPIdev->set_clk_pin)
    {
        while(1);
    }
    if(!pSPIdev->clr_clk_pin)
    {
        while(1);
    }

    // SDO
    if(!pSPIdev->cfg_sdo_dir)
    {
        while(1);
    }
    if(!pSPIdev->set_sdo_pin)
    {
        while(1);
    }
    if(!pSPIdev->clr_sdo_pin)
    {
        while(1);
    }

    // SDI
    if(!pSPIdev->cfg_sdi_dir)
    {
        while(1);
    }
    if(!pSPIdev->get_sdi_pin)
    {
        while(1);
    }

#if 0
    // init
    if(pSPIdev->init)
    {
        pSPIdev->init();
    }else
    {
        while(1);
        spi_debug("Warning ! fun not set for device init\n");
        spi_debug("Warning ! You may need to ENABLE CLOCK\n");
    }
#else
    pSPIdev->cfg_nss_dir(IOPORT_DIR_OUTPUT);

    pSPIdev->cfg_clk_dir(IOPORT_DIR_OUTPUT);

    pSPIdev->cfg_sdo_dir(IOPORT_DIR_OUTPUT);

    pSPIdev->cfg_sdi_dir(IOPORT_DIR_INPUT);

    pSPIdev->cfg_nss_dir(IOPORT_DIR_OUTPUT);
    pSPIdev->set_nss_pin();
#endif

    switch(pSPIdev->cmm_mode)
    {
        case Mode_1:
        case Mode_2:
            pSPIdev->clr_clk_pin();
            break;
        case Mode_3:
        case Mode_4:
            pSPIdev->set_clk_pin();
            break;
    }
}

/*********************************************************************
 * @fn      SPISimulate_CSIsEnable
 *
 * @brief   模拟SPI片选使能
 *
 *
 * @param   none
 *
 * @return  none
 */
void SPISimulate_CSIsEnable(struct spi_device_info *pSPIdev, int IsEnable )
{
    if(!pSPIdev)
    {
        return;
    }

    if( IsEnable )
    {
        if(pSPIdev->clr_nss_pin)
        {
            pSPIdev->clr_nss_pin();
        }
    }
    else
    {
        if(pSPIdev->set_nss_pin)
        {
            pSPIdev->set_nss_pin();
        }
    }
}

/*********************************************************************
 * @fn      SPISimulate_WriteByte
 *
 * @brief   模拟SPI写一个字节数据
 *
 *
 * @param   none
 *
 * @return  none
 */
void SPISimulate_WriteByte(struct spi_device_info *pSPIdev, unsigned char nByte )
{
    int i = 0;

    if(!pSPIdev)
    {
        while(1);
    }

    switch( pSPIdev->cmm_mode )
    {
        case Mode_1://当SCLK=0时处于空闲态，数据采样是在上升沿，数据发送是在下降沿

            pSPIdev->clr_clk_pin();

            for( i = 8; i > 0; i-- )//高位在前
            {
                if( nByte & 0x80 )
                {
                    pSPIdev->set_sdo_pin();
                }
                else
                {
                    pSPIdev->clr_sdo_pin();
                }

                pSPIdev->set_clk_pin();
                nByte <<= 1;
                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->clr_clk_pin();
                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->clr_clk_pin();
            break;

        case Mode_2://当SCLK=0时处于空闲态，数据采样是在下降沿，数据发送是在上升沿
            pSPIdev->clr_clk_pin();

            for( i = 8; i > 0; i-- )//高位在前
            {
                pSPIdev->clr_sdo_pin();

                if( nByte & 0x80 )
                {
                    pSPIdev->set_sdo_pin();
                }
                else
                {
                    pSPIdev->clr_sdo_pin();
                }

                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->set_clk_pin();
                nByte <<= 1;
                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->clr_clk_pin();
            break;

        case Mode_3://当SCLK=1时处于空闲态，数据采集是在下降沿，数据发送是在上升沿
            pSPIdev->set_clk_pin();

            for( i = 8; i > 0; i-- )//高位在前
            {
                pSPIdev->clr_clk_pin();

                if( nByte & 0x80 )
                {
                    pSPIdev->set_sdo_pin();
                }
                else
                {
                    pSPIdev->clr_sdo_pin();
                }

                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->set_clk_pin();
                nByte <<= 1;
                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->set_clk_pin();
            break;

        case Mode_4://当SCLK=1时处于空闲态，数据采集是在上升沿，数据发送是在下降沿
            pSPIdev->clr_clk_pin();

            for( i = 8; i > 0; i-- )//高位在前
            {
                pSPIdev->set_clk_pin();

                if( nByte & 0x80 )
                {
                    pSPIdev->set_sdo_pin();
                }
                else
                {
                    pSPIdev->clr_sdo_pin();
                }

                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->clr_clk_pin();
                nByte <<= 1;
                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->set_clk_pin();
            break;
    }
}
/*********************************************************************
 * @fn      SPISimulateWrite
 *
 * @brief   模拟SPI写数据
 *
 *
 * @param   none
 *
 * @return  none
 */
void SPISimulateWrite(struct spi_device_info *pSPIdev, unsigned char *pdata, int len )
{
    int i;

    if( pSPIdev == (void *)0 || pdata == (void *)0 || len <= 0 )
        return;

    SPISimulate_CSIsEnable(pSPIdev, 1 );
    pSPIdev->do_delay_us(8);

    for( i = 0; i < len; i++ )
    {
        SPISimulate_WriteByte(pSPIdev, pdata[i] );
    }

    pSPIdev->do_delay_us(8);
    SPISimulate_CSIsEnable(pSPIdev, 0 );
}
/*********************************************************************
 * @fn      SPISimulate_ReadByte
 *
 * @brief   模拟SPI读取一个字节
 *
 *
 * @param   none
 *
 * @return  none
 */
unsigned char SPISimulate_ReadByte(struct spi_device_info *pSPIdev)
{
    int i = 0;
    unsigned char Rdata = 0;
    //unsigned char IoVal = 1<<pSPIdev->nMISO.pin;

    if( pSPIdev == (void *)0 )
        return 0;

    switch( pSPIdev->cmm_mode )
    {
        case Mode_1://当SCLK=0时处于空闲态，数据采样是在上升沿，数据发送是在下降沿
            pSPIdev->clr_clk_pin();

            for( i = 0; i < 8; i++ )
            {
                pSPIdev->set_clk_pin();

                Rdata <<= 1;
                //Rdata |= (xIoPort_pin_get(pSPIdev->nMISO.port, pSPIdev->nMISO.pin) == IoVal)? 1 : 0;
                if(pSPIdev->get_sdi_pin() > 0)
                {
                    Rdata |= 0x1;
                }

                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->clr_clk_pin();
                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->clr_clk_pin();
            break;

        case Mode_2://当SCLK=0时处于空闲态，数据采样是在下降沿，数据发送是在上升沿
            pSPIdev->clr_clk_pin();

            for( i = 0; i < 8; i++ )
            {
                pSPIdev->set_clk_pin();
                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->clr_clk_pin();


                //Rdata |= (xIoPort_pin_get(pSPIdev->nMISO.port, pSPIdev->nMISO.pin) == IoVal)? 1 : 0;
                if(pSPIdev->get_sdi_pin() > 0)
                {
                    Rdata |= 0x1;
                }
                Rdata <<= 1;
                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->clr_clk_pin();
            break;

        case Mode_3://当SCLK=1时处于空闲态，数据采集是在下降沿，数据发送是在上升沿
            pSPIdev->set_clk_pin();

            for( i = 0; i < 8; i++ )
            {
                pSPIdev->set_clk_pin();
                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->clr_clk_pin();

                Rdata <<= 1;
                //Rdata |= (xIoPort_pin_get(pSPIdev->nMISO.port, pSPIdev->nMISO.pin) == IoVal)? 1 : 0;
                if(pSPIdev->get_sdi_pin() > 0)
                {
                    Rdata |= 0x1;
                }

                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->set_clk_pin();
            break;

        case Mode_4://当SCLK=1时处于空闲态，数据采集是在上升沿，数据发送是在下降沿
            pSPIdev->set_clk_pin();

            for( i = 0; i < 8; i++ )
            {
                pSPIdev->clr_clk_pin();
                pSPIdev->do_delay_us(SPI_DELAY_RW);
                pSPIdev->set_clk_pin();

                Rdata <<= 1;
                //Rdata |= (xIoPort_pin_get(pSPIdev->nMISO.port, pSPIdev->nMISO.pin) == IoVal)? 1 : 0;
                if(pSPIdev->get_sdi_pin() > 0)
                {
                    Rdata |= 0x1;
                }

                pSPIdev->do_delay_us(SPI_DELAY_RW);
            }

            pSPIdev->set_clk_pin();
            break;
    }

    return Rdata;
}
/*********************************************************************
 * @fn      SPISimulateRead
 *
 * @brief   模拟SPI读数据
 *
 *
 * @param   none
 *
 * @return  none
 */
void SPISimulateRead(struct spi_device_info *pSPIdev, unsigned char *pdata, int len )
{
    int i;

    if( pSPIdev == (void *)0 || pdata == (void *)0 || len <= 0 )
        return;

    SPISimulate_CSIsEnable(pSPIdev, 1);
    pSPIdev->do_delay_us(8);

    for( i = 0; i < len; i++ )
    {
        //    SPISimulate_WriteByte( pSPIdev, 0x00 );
        pdata[i] = SPISimulate_ReadByte(pSPIdev);
    }

    pSPIdev->do_delay_us(8);
    SPISimulate_CSIsEnable(pSPIdev, 0);
}

